package maxEntClassifier;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;

public abstract class Classifier {
	public String modelFile;
	public String trainSet;
	public String testSet;
	public static String[] outcomeNames;
	public static String testOut;
	
	public Classifier(String _trainSet,String _testSet)  {
		trainSet=_trainSet;
		testSet=_testSet;
	}
	
	public abstract void loadModel() throws IOException;
	
	public abstract void train() throws FileNotFoundException, IOException;
	public abstract String inference(String[] features) throws IOException;

	public void test() throws IOException{
		
		loadModel();
		
		BufferedReader br=new BufferedReader(new FileReader(testSet));
		BufferedWriter bw = new BufferedWriter(new FileWriter(testOut));
		// count precision, recall
		HashMap<String,Integer> totalMarkedPos = new HashMap<String,Integer>();
		HashMap<String,Integer> totalPos = new HashMap<String,Integer>();
		HashMap<String,Integer> truePos = new HashMap<String,Integer>();

		while(true){
			String line=br.readLine();
			if(null==line||line.trim().equals("")) break;
			String[] sa=line.split(" ");
			String[] context=new String[sa.length-1];
			for(int i=0;i<context.length;i++){
				context[i]=sa[i];
			}
			String trueLabel=sa[sa.length-1];

			String markedLabel = inference(context);
			if(null==markedLabel) continue;
			String res="";
			for(int i=0;i<context.length;i++)
				res+=context[i]+" ";
			res+=trueLabel;
			U.add1(totalMarkedPos,markedLabel);
			U.add1(totalPos,trueLabel);
			if (trueLabel.equals(markedLabel))
				U.add1(truePos,trueLabel);
			else
				res+=" ////WRONG//// "+markedLabel;
			bw.write(res+"\n");
		}

		printResult(totalMarkedPos, totalPos, truePos);	
		br.close();
		bw.close();
	}
	
	public static void printResItem(HashMap<String,Integer> totalMarkedPos, HashMap<String,Integer> totalPos,
			HashMap<String,Integer> truePos, String label) {
		double prec = (U.tryGet(totalMarkedPos,label) == 0) ? 0 : U
				.truncation((double) U.tryGet(truePos,label) * 100 / U.tryGet(totalMarkedPos,label));
		double recall = (U.tryGet(totalPos,label) == 0) ? 0 : U
				.truncation((double) U.tryGet(truePos,label) * 100 / U.tryGet(totalPos,label));
		System.out.println(label+"("+U.getIndex(outcomeNames,label)+")"+":\t" + U.tryGet(truePos,label) + "\t" + U.tryGet(totalMarkedPos,label) + "\t"
				+ U.tryGet(totalPos,label) + "\t" + prec + "\t" + recall + "\t"
				+ U.truncation(2 * prec * recall / (prec + recall)));
	}
	
	public static void printResult(HashMap<String,Integer> totalMarkedPos, HashMap<String,Integer> totalPos,
			HashMap<String,Integer> truePos) {
		System.out.println("\n\nresult :");
		System.out.println();
		System.out.println("Label\tTrue+\tMarked+\tActual+\tPrec.\tRecall\tF1");

		for(String label:totalMarkedPos.keySet())
			printResItem(totalMarkedPos, totalPos, truePos, label);


		int correctTokens = 0, markedTokens = 0, acturalTokens = 0;
		for(String label:totalMarkedPos.keySet()){
			correctTokens += U.tryGet(truePos,label);
			markedTokens += U.tryGet(totalMarkedPos,label);
			acturalTokens += U.tryGet(totalPos,label);
		}

		System.out
				.println("---------------------------------------------------------");
		double prec = (markedTokens == 0) ? 0 : U
				.truncation((double) correctTokens * 100 / markedTokens);
		double recall = (acturalTokens == 0) ? 0 : U
				.truncation((double) correctTokens * 100 / acturalTokens);
		double f =2 * prec * recall / (prec + recall);
		System.out.println("OV:\t" + correctTokens + "\t" + markedTokens + "\t"
				+ acturalTokens + "\t" + prec + "\t" + recall + "\t"
				+ f);
//		System.out.println("train set length: "+trainSetLength);
//		System.out.println();
		//System.out.println(lambdaLength+"\t"+f+"\t\t"+inteval);
	}

	public static double countTesetP1fRatio(String testSet,HashSet<String> p1fSet) throws IOException{

		double d1fN=0;
		int sentenceN=0;
		BufferedReader r = U.newReader(testSet);
		while (true) {
			String l=r.readLine();
			if(null==l) break;
			sentenceN++;
			String[] sa =l.split(" ");
			for (int i = 0; i < sa.length-1; i++) {
				if(p1fSet.contains(sa[i]+":"+sa[sa.length-1])){
					d1fN++;
				}
			}
		}
		r.close();
		return d1fN/sentenceN;
	}
	
	public static double countTestOutSetP1fRatio(String testOut,HashSet<String> p1fSet) throws IOException{

		double d1fN=0;
		int sentenceN=0;
		BufferedReader r = U.newReader(testOut);
		while (true) {
			String l=r.readLine();
			if(null==l) break;
			String[] sa =l.split(" ");
			if(sa.length<2)continue;
			if(!sa[sa.length-2].equals("////WRONG////")) continue;
			sentenceN++;
			
			for (int i = 0; i < sa.length-3; i++) {
				if(p1fSet.contains(sa[i]+":"+sa[sa.length-1]))
					d1fN++;
			}
		}
		r.close();
		return d1fN/sentenceN;
	}
	
}
